/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * File Name          : freertos.c
 * Description        : Code for freertos applications
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2024 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ina226_app.h"
#include "KeySw.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

/* USER CODE END Variables */
osThreadId System_AppHandle;
osThreadId INA226_AppHandle;
osThreadId OLED_AppHandle;
osThreadId Key_AppHandle;

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

void System_App_Task(void const *argument);
void INA226_App_Task(void const *argument);
void OLED_App_Task(void const *argument);
void Key_App_Task(void const *argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/* GetIdleTaskMemory prototype (linked to static allocation support) */
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize);

/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];

void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize)
{
    *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
    *ppxIdleTaskStackBuffer = &xIdleStack[0];
    *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
    /* place for user code */
}
/* USER CODE END GET_IDLE_TASK_MEMORY */

/**
 * @brief  FreeRTOS initialization
 * @param  None
 * @retval None
 */
void MX_FREERTOS_Init(void)
{
    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* USER CODE BEGIN RTOS_MUTEX */
    /* add mutexes, ... */
    /* USER CODE END RTOS_MUTEX */

    /* USER CODE BEGIN RTOS_SEMAPHORES */
    /* add semaphores, ... */
    /* USER CODE END RTOS_SEMAPHORES */

    /* USER CODE BEGIN RTOS_TIMERS */
    /* start timers, add new ones, ... */
    /* USER CODE END RTOS_TIMERS */

    /* USER CODE BEGIN RTOS_QUEUES */
    /* add queues, ... */
    /* USER CODE END RTOS_QUEUES */

    /* Create the thread(s) */
    /* definition and creation of System_App */
    osThreadDef(System_App, System_App_Task, osPriorityIdle, 0, 128);
    System_AppHandle = osThreadCreate(osThread(System_App), NULL);

    /* definition and creation of INA226_App */
    osThreadDef(INA226_App, INA226_App_Task, osPriorityNormal, 0, 256);
    INA226_AppHandle = osThreadCreate(osThread(INA226_App), NULL);

    /* definition and creation of OLED_App */
    osThreadDef(OLED_App, OLED_App_Task, osPriorityNormal, 0, 128);
    OLED_AppHandle = osThreadCreate(osThread(OLED_App), NULL);

    /* definition and creation of Key_App */
    osThreadDef(Key_App, Key_App_Task, osPriorityHigh, 0, 128);
    Key_AppHandle = osThreadCreate(osThread(Key_App), NULL);

    /* USER CODE BEGIN RTOS_THREADS */
    /* add threads, ... */
    /* USER CODE END RTOS_THREADS */
}

/* USER CODE BEGIN Header_System_App_Task */
/**
 * @brief  Function implementing the System_App thread.
 * @param  argument: Not used
 * @retval None
 */
/* USER CODE END Header_System_App_Task */
void System_App_Task(void const *argument)
{
    /* USER CODE BEGIN System_App_Task */
    printf("System running. \r\n");
    /* Infinite loop */
    for (;;)
    {
        osDelay(5000);
    }
    /* USER CODE END System_App_Task */
}

/* USER CODE BEGIN Header_INA226_App_Task */
/**
 * @brief Function implementing the INA226_APP thread.
 * @param argument: Not used
 * @retval None
 */
/* USER CODE END Header_INA226_App_Task */
void INA226_App_Task(void const *argument)
{
    /* USER CODE BEGIN INA226_App_Task */
    uint8_t channel_index = 0;
    uint16_t devid = 0;
    uint32_t Time_Manager_Tick = 0;
    const TickType_t xTicksToWait = pdMS_TO_TICKS(1000);
    double current = 0, vbus = 0;

    vTaskDelay(pdMS_TO_TICKS(50));

    portENTER_CRITICAL();
    INA226_App_Init();
    portEXIT_CRITICAL();
    Time_Manager_Tick = xTaskGetTickCount();
    INA226_App_Get_ID(channel_index, &devid);
    printf("channel_index: %d, id: %04X \r\n", channel_index, devid);
    /* Infinite loop */
    for (;;)
    {
        // portENTER_CRITICAL();
        vTaskSuspendAll();
        INA226_App_Measure_AllData(channel_index);
        xTaskResumeAll();
        // portEXIT_CRITICAL();
        INA226_App_Get_Current(channel_index, &current);
        INA226_App_Get_VbusVoltage(channel_index, &vbus);
        printf("channel_index: %d, current: %lf, vbus: %lf \r\n", channel_index, current, vbus);
        // for (channel_index = 0; channel_index < INA226_NUMBER; channel_index++)
        // {
        //     portENTER_CRITICAL();
        //     INA226_App_Measure_AllData(channel_index);
        //     portEXIT_CRITICAL();
        //     INA226_App_Get_Current(channel_index, &current);
        //     INA226_App_Get_VbusVoltage(channel_index, &vbus);
        //     printf("channel_index: %d, current: %lf, vbus: %lf \r\n", channel_index, current, vbus);
        // }
        vTaskDelayUntil(&Time_Manager_Tick, xTicksToWait);
    }
    /* USER CODE END INA226_App_Task */
}

/* USER CODE BEGIN Header_OLED_App_Task */
/**
 * @brief Function implementing the OLED_App thread.
 * @param argument: Not used
 * @retval None
 */
/* USER CODE END Header_OLED_App_Task */
void OLED_App_Task(void const *argument)
{
    /* USER CODE BEGIN OLED_App_Task */
    /* Infinite loop */
    for (;;)
    {
        osDelay(100);
    }
    /* USER CODE END OLED_App_Task */
}

/* USER CODE BEGIN Header_Key_App_Task */
/**
 * @brief Function implementing the Key_Task thread.
 * @param argument: Not used
 * @retval None
 */
/* USER CODE END Header_Key_App_Task */
void Key_App_Task(void const *argument)
{
    /* USER CODE BEGIN Key_App_Task */
    uint32_t Time_Manager_Tick = 0;
    const TickType_t xTicksToWait = pdMS_TO_TICKS(5);
    KeySw_ID_TypeDef Pin_ID;

    Time_Manager_Tick = xTaskGetTickCount();
    /* Infinite loop */
    for (;;)
    {
        KeySw_Scanf_Task();
        while (KeySw_GetTrigger(&Pin_ID, 1) == 1)
        {
            printf("KeySw_Id: %d, State: %d to %d\r\n", Pin_ID, (KeySw_GetPin(Pin_ID)) ? (0) : (1), KeySw_GetPin(Pin_ID));
        }
        vTaskDelayUntil(&Time_Manager_Tick, xTicksToWait);
    }
    /* USER CODE END Key_App_Task */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */
